package cn.edu.seu.java.ast.visitor;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;

import cn.edu.seu.java.node.ASTClass;
import cn.edu.seu.java.node.ASTMethod;
import cn.edu.seu.java.util.ASTNodeUtil;

/**
* extract classes including top-level class, member class, but except enum class and 
* local class appeared in a method, if-statement, etc.
*/
public class CompilationUnitVisitor extends ASTVisitor {
	private CompilationUnit unit;
	private List<ASTClass> listOfASTClass;
	private List<ASTMethod> listOfASTMethod;

	public CompilationUnitVisitor(List<CompilationUnit> units) {
		this.listOfASTClass = new ArrayList<ASTClass>();
		this.listOfASTMethod = new ArrayList<ASTMethod>();
		for (CompilationUnit unit : units) {
			this.unit = unit;
			unit.accept(this);
		}
	}

	public CompilationUnitVisitor(CompilationUnit unit) {
		this.listOfASTClass = new ArrayList<ASTClass>();
		this.listOfASTMethod = new ArrayList<ASTMethod>();
		this.unit = unit;
		unit.accept(this);
	}

	/**
	 * Bug: how to fix??
	 * If the top-level class has several member classes, this method will collect this top-level class and their 
	 * member classes at the same time. 
	 * 
	 */
	@Override
	public boolean visit(TypeDeclaration node) {
		if (node.isLocalTypeDeclaration() != true) {
			String projectName = (String) unit.getProperty("projectName");
			String versionNum = (String) unit.getProperty("versionNum");
			String versionPath = (String) unit.getProperty("versionPath");
			String sourceFilePath = (String) unit.getProperty("sourceFilePath");
			String relativeSourceFilePath = (String) unit.getProperty("relativeSourceFilePath");
			String packageName = (String) unit.getProperty("packageName");
			
			ASTClass classNode = new ASTClass(sourceFilePath, node);
			classNode.setProjectName(projectName);
			classNode.setVersionNum(versionNum);
			classNode.setVersionPath(versionPath);
			classNode.setPackageName(packageName);
			classNode.setUnitName(new File(sourceFilePath).getName().replace(".java",""));
			classNode.setRelativeSourcePath(relativeSourceFilePath);
			listOfASTClass.add(classNode);
		}
		return true;
	}

	@Override
	public boolean visit(MethodDeclaration node) {
		if (ASTNodeUtil.isInLocalClass(node) != true && ASTNodeUtil.isInEnumClass(node) != true) {
			String projectName = (String) unit.getProperty("projectName");
			String versionNum = (String) unit.getProperty("versionNum");
			String versionPath = (String) unit.getProperty("versionPath");
			String sourceFilePath = (String) unit.getProperty("sourceFilePath");
			String relativeSourceFilePath = (String) unit.getProperty("relativeSourceFilePath");
			String packageName = (String) unit.getProperty("packageName");
					
			ASTMethod methodNode = new ASTMethod(packageName, sourceFilePath, node);
			methodNode.setProjectName(projectName);
			methodNode.setVersionNum(versionNum);
			methodNode.setVersionPath(versionPath);
			methodNode.setRelativeSourcePath(relativeSourceFilePath);
			methodNode.setFullyQualifiedTopClassName(ASTNodeUtil.getFullyQualifiedTopClassName(node));
			
			listOfASTMethod.add(methodNode);
		}
		return false;
	}

	/**
	* extract classes including top-level class, member class, but except enum class and 
	* local class appeared in a method, if-statement, etc.
	*/
	public List<ASTClass> getListOfASTClass() {
		return listOfASTClass;
	}

	/**
	 * 
	 * extract methods in class (but except local or enum class)
	 * 
	 */
	public List<ASTMethod> getListOfASTMethod() {
		return listOfASTMethod;
	}
}
